#pragma once

#include "../base/obj_pointer.h"
#include "../base/list.h"
#include <type_traits>
#include <condition_variable>

OPEN_JLIB_NS


template<typename _Type, List _Type::*_Joint>
struct BlockQueue {

  static_assert(std::is_base_of<Obj, _Type>::value, "");

  typedef Ptr<_Type> value_type;


  inline void push (value_type value) noexcept {
    value->retain();
    std::unique_lock<std::mutex> lock {_mutex};
    _queue.push_back(&(value.ptr()->*_Joint));
    _size++;
    _cv.notify_one();
  }


  inline value_type poll () noexcept {
    std::unique_lock<std::mutex> lock {_mutex};
    for (;;) {
      if (_queue.only()) {
        _cv.wait(lock);
        continue;
      }
      auto joint = _queue.next();
      joint->detach();
      _size--;
      auto value = joint->cast(_Joint);
      return {value, true};
    }
  }



protected:
  std::mutex _mutex;
  std::condition_variable _cv;
  List _queue;
  volatile uwl _size {0};
};


CLOSE_JLIB_NS
